#include <stdio.h>
#include <stdarg.h>
#include <assert.h>

typedef struct vaArg
{
     char char1;
     int int1;
     char char2;
     double double1;
     char char3;
}VaArg;


char str[] = {'a', 'b', 'c', '\0'};
char str2[] = "abc";
char color_name1[][6] = { //数组的数组
    "red", 
    "green", 
    "blue", 
};
char color_name2[][6] = {  //数组的数组
    {'r', 'e', 'd', '\0'}, 
    {'g', 'r', 'e', 'e', 'n', '\0'}, 
    {'b', 'l', 'u', 'e', '\0'}, 
};
//以下写法比较好，加颜色，其他代码不需要修改，并且不需要到处用sizeof计算COLOR_COUNT
char *color_name[] ={//指针的数组
     "red",
     "green",
     "yellow"
     };//，标识符 color_name 的类型是“指向char 的指针的数组”
#define COLOR_COUNT (sizeof(color_name)/sizeof(color_name[0]));


void tiny_printf(char *format,...){
     int i;
     va_list args;
     va_start(args,format);
     for ( i = 0;  format[i] !='\0'; i++)
     {
          switch (format[i])
          {
          case 's':
               printf("%s",va_arg(args,char*));
               break;
          case 'd':
               printf("%d",va_arg(args,int));
               break;
          default:
               assert(0);
               break;
          }
     }
     
     va_end(args);
     putchar('\n');



}
void func(int *hoge){

}
void funcMuilt(int (*hoge)[2]){

}

char *my_strcpy(char *dest, const char * const src) 
{ 
    //src = NULL;  //<-- 报错！ 
   // *src = 'a';  //<-- 报错！ 
}

char *my_strcpy1(char *dest, const char *src) 
{ 
    //*src = 'a';  //<-- 报错！ 
}
char *my_strcpy2(char *dest, char * const src) 
{ 
    //src = NULL;  //<-- 报错！ 
}

char *my_strcpy3(char *dest, const char *src) 
{ 
    src = NULL;  //<-- 即使给src赋值，编译器也不会报错 
}
int main(void){
     tiny_printf("sdd","hello world",5,3);
     printf("struct arArg size=%zd\n",sizeof(struct vaArg));//因为对齐的原因，所以size=32，而不是15

     /**
      * 这里，* 是一个前缀运算符，其优先级低于 ()，所以声明中
     必须使用圆括号以确保正确的结合顺序
     */
     int *f();// f: function returning pointer to int 
     int (*fp)();//pf: pointer to function returning int

     int (*func_table[10])(int a);// 函数指针数组，数组的元素是函数指针，函数指针的返回值是int ，参数是int 
     //或 指向返回 int 的函数（参数为 int a）的指针的数组（元素个数为 10）
     int arr[3];
     int (*arr_p)[3];
     arr_p = &arr;//在数组前加上&，获取指向数组的指针

     //arr_p = arr;//报错：这是因为，“指向 int 的指针”与“指向 int 的数组（元素个数为 3）的指针”是完全不同的类型。
     /**
      * 然而，如果把它们看作地址，则 array 和 &array 指向的（很
可能）是相同的地址。那么它们到底有何不同呢？那就是在使用它们
进行指针运算时，结果不同。
     在我的机器上，int 类型的长度是 4 字节，所以对“指向 int
的指针”加 1，指针会前进 4 字节。而对于“指向 int 的数组（元
素个数为 3）的指针”，由于它指向的类型是“int 的数组（元素个
数为 3）”，其长度为 12 字节（假设 int 的长度为 4 字节），所
以加 1 后，指针前进 12 字节（图 3-6）。
      */
     func(arr);

     int arrMuil[3][2];//arrMuil是int的数组（元素个数2为）的数组（元素个数3为）.或理解为[2]数组的数组[3]
     // funcMuilt(arrMuil[3]);//error> note: expected 'int (*)[2]' but argument is of type 'int *'
     // funcMuilt(arrMuil[3][0]);//error> note: expected 'int (*)[2]' but argument is of type 'int'
     funcMuilt(arrMuil);

     printf("size of int(*[5])(double)=%d\n",sizeof(int (*[5])(double)));//指向返回 int 的函数（参数为 double）的指针的数组（元素个数为 5）
     
     char * const src;//src是指向char的只读的指针 
     char const *src2;//const char *src2 //意思完全相同

     char str[4]; 
     printf("str[2]=%c\n",str[2]);
     //str = "abc";//error
     char *strp = "abc";
     //*str = "abc";//error: assignment to 'char' from 'char *' makes integer from pointer without a cast [-Wint-conversion]
     str[2] = 'd';//ok

     printf("after str[2]=%c\n",str[2]);
     int int_value ;
     int_value = *(str+2);
     printf("int_value的值为%d\n",int_value);
     char *str_2; 
     str_2 = "abc";  //<-- 将指向"abc"初始元素的指针赋值给str
     //strp[0] ='d';//下面的语句不输出，编译器无任何警告
     printf("strp's content =%s\n",strp);

     int hoge[][3] = { //“最外层”以外的数组的元素个数是不能省略的。
          {1, 2, 3}, 
          {4, 5, 6}, 
          {7, 8, 9}, 
          {7, 8, 9},
    };
    char str_m[] = "abc";//（4个字符编译器自己去计算） char 的数组可以特别地通过以下形式进行初始化 = char str[] = {'a', 'b', 'c', '\0'};
    char *str_p = "abc";//常用写法，以下是两者的区别
    /**
     * 两者的差别在于，前者是对“char 的数组”的内容进行初始
     * 化，而后者是将“指向 char 的指针”指向字符串字面量。由于字符
     * 串字面量通常被分配在只读空间中，所以如果采用后者的写法，则无
     * 法改写字符串的内容。
     */
     return 0;

}
